/*
 * NumLabChart.fx
 *

 Numerical Lab Chart
 
 * Created on Mar 2, 2010, 3:13:49 PM
 */

package GraphsWindowPackage.LabPackage;

import javafx.scene.shape.Rectangle;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.text.Text;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.util.Math;
import GraphsWindowPackage.LabMedNode;
import AlertSystem.Window;
import javafx.scene.input.MouseEvent;


/**
 * @author quang
 */

public class NumLabChart extends Window {

    public var startShownTime: Number;
    public var endShownTime: Number;
    public var lab: Lab;
    public var numPixPerTimeUnit: Number;

    //////////////////////////////////////////////////

    var zoomRatio: Number = zoomMultiplier;
    
    var xSeries: Number[] = bind lab.timeSeries;
    var ySeries: Number[] = bind lab.labValSeq;

    //max of normal range
    var maxRange: Number = lab.rangeMax;

    //min of normal range
    var minRange: Number = lab.rangeMin;

    //height of chart in pixel
    var height: Number = bind labChartHeight * zoomRatio;

    var xAxis: MyAxis = bind MyAxis {
                    lowerBound: startShownTime
                    upperBound: endShownTime
                    numPixPerUnit: numPixPerTimeUnit
                };

    var yAxis: MyAxis = MyAxis {
                    lowerBound: lab.lowerBound
                    upperBound: lab.upperBound
                    numPixPerUnit: bind (labChartHeight * zoomRatio) / (lab.upperBound - lab.lowerBound)
                };

    //step for y label
    var yStep: Number = lab.yStep;

    //width of the x label
    def yLabelSpace = yLabelWidth;

    function createYLabel(): Text[] {
        def yPixStep: Number = bind height / (yAxis.upperBound - yAxis.lowerBound) * yStep;
        def numTick = Math.ceil((yAxis.upperBound - yAxis.lowerBound) / yStep);

        return [
            for (i in [0..numTick-1]) {
                Text {
                    x: 0
                    y: bind (3 + height - yPixStep * i)
                    content: if (yStep < 1) "{yAxis.lowerBound + yStep * i} -"
                                else "{%.0f (yAxis.lowerBound + yStep * i)} -"
                }
            },
            Text {
                x: 0
                y: 3
                content: if (yStep < 1) "{yAxis.upperBound} -"
                            else "{%.0f (yAxis.upperBound)} -"
            }
        ]
    }

    function createShapes(xSeries: Number[]): Node[] {
        if (xSeries.isEmpty()) return null;
        
        var shapes: Node[] = null;
        insert Rectangle {
            translateX: yLabelSpace
            width: chartWidth - yLabelWidth //plotWidth
            height: bind height //plotHeight
            fill: Color.WHITE
            smooth: false
            stroke: Color.BLACK
        } into shapes;

        //rectangle showing the normal range
        insert Rectangle {
                translateX: yLabelSpace + 1 //so that range view doesn't overlap left side of plot rectangle
                translateY: bind ((yAxis.upperBound - maxRange) * yAxis.numPixPerUnit) + 1
                width: chartWidth - yLabelWidth - 2 //plotWidth - 2    //-1 so that range view doesn't overlap right side of plot rectangle
                height: bind ((maxRange - minRange) * yAxis.numPixPerUnit) - 2
                fill: Color.CYAN
                smooth: false
            } into shapes;

        //label for x axis
        insert createYLabel() into shapes;

        return shapes;
    }


    function createPointSeq(xSeries: Number[], ySeries: Number[]): LabMedNode[] {
        return
        for (i in [0..sizeof xSeries - 1]) {
            LabMedNode {
                shape: Circle {
                    translateX: yLabelSpace
                    centerX: (xSeries[i] - xAxis.lowerBound) * xAxis.numPixPerUnit;
                    centerY: bind ((yAxis.upperBound - ySeries[i]) * yAxis.numPixPerUnit);
                    radius: dataPointRadius
                    smooth: true
                    fill: if (ySeries[i] > maxRange) Color.RED
                            else if (ySeries[i] < minRange) Color.BLUE
                                else Color.DARKGRAY
                }                
                info: "{Math.round(Math.floor(xSeries[i]))} days {Math.round ((xSeries[i] - Math.floor(xSeries[i])) * 24)} hours from the beginning of treatment period\n"
                        "Lab value: {ySeries[i]}"
            }
        }
    }

    public override function create(): Node {


        //sequence of data points
        var pointSeq = bind createPointSeq(xSeries, ySeries);

        var shapes = bind createShapes(xSeries);
        
        return Group {
            content: bind [ shapes, pointSeq ]
            onMouseClicked: function(e: MouseEvent): Void {
                if (zoomRatio == 1.0) zoomRatio = zoomMultiplier
                else zoomRatio = 1.0;
            }
        }
    }
}


//public class NumLabChart extends Window {
//
//    public var xSeries: Number[];
//    public var ySeries: Number[];
//
//    //max of normal range
//    public var maxRange: Number;
//
//    //min of normal range
//    public var minRange: Number;
//
//    //width of chart in pixel
//    public var width: Number;
//
//    //height of chart in pixel
//    public var height: Number;
//
//    //width of the plot area in pixel
//    public var plotWidth: Number;
//
//    //height of the plot area pixel
//    public var plotHeight: Number;
//
//    public var xAxis: MyAxis;
//    public var yAxis: MyAxis;
//
//    //step for y label
//    public var yStep: Number;
//
//    //width of the x label
//    def yLabelSpace = width - plotWidth;
//
//    //height of the y label
//    def xLabelSpace = height - plotHeight;
//
//    function createYLabel(): Text[] {
//        def yPixStep: Number = bind height / (yAxis.upperBound - yAxis.lowerBound) * yStep;
//        def numTick = Math.ceil((yAxis.upperBound - yAxis.lowerBound) / yStep);
//
//        return [
//            for (i in [0..numTick-1]) {
//                Text {
//                    x: 0
//                    y: bind (3 + height - yPixStep * i)
//                    content: if (yStep < 1) "{yAxis.lowerBound + yStep * i} -"
//                                else "{%.0f (yAxis.lowerBound + yStep * i)} -"
//                }
//            },
//            Text {
//                x: 0
//                y: 3
//                content: if (yStep < 1) "{yAxis.upperBound} -"
//                            else "{%.0f (yAxis.upperBound)} -"
//            }
//        ]
//    }
//
//    function createShapes(xSeries: Number[]): Node[] {
//        if (xSeries.isEmpty()) return null;
//
//        var shapes: Node[] = null;
//        insert Rectangle {
//            translateX: yLabelSpace
//            translateY: xLabelSpace
//            width: plotWidth
//            height: bind plotHeight
//            fill: Color.WHITE
//            smooth: false
//            stroke: Color.BLACK
//        } into shapes;
//
//        //rectangle showing the normal range
//        insert Rectangle {
//                translateX: yLabelSpace + 1 //so that range view doesn't overlap left side of plot rectangle
//                translateY: bind (xLabelSpace + (yAxis.upperBound - maxRange) * yAxis.numPixPerUnit) + 1
//                width: plotWidth - 2    //-1 so that range view doesn't overlap right side of plot rectangle
//                height: bind ((maxRange - minRange) * yAxis.numPixPerUnit) - 2
//                fill: Color.CYAN
//                smooth: false
//            } into shapes;
//
//        //label for x axis
//        insert createYLabel() into shapes;
//
//        return shapes;
//    }
//
//
//    function createPointSeq(xSeries: Number[], ySeries: Number[]): LabMedNode[] {
//        return
//        for (i in [0..sizeof xSeries - 1]) {
//            LabMedNode {
//                shape: Circle {
//                    translateX: yLabelSpace
//                    translateY: xLabelSpace
//                    centerX: (xSeries[i] - xAxis.lowerBound) * xAxis.numPixPerUnit;
//                    centerY: bind ((yAxis.upperBound - ySeries[i]) * yAxis.numPixPerUnit);
//                    radius: dataPointRadius
//                    smooth: true
//                    fill: if (ySeries[i] > maxRange) Color.RED
//                            else if (ySeries[i] < minRange) Color.BLUE
//                                else Color.DARKGRAY
//                }
//                info: "{Math.round(Math.floor(xSeries[i]))} days {Math.round ((xSeries[i] - Math.floor(xSeries[i])) * 24)} hours from the beginning of treatment period\n"
//                        "Lab value: {ySeries[i]}"
//            }
//        }
//    }
//
//    public override function create(): Node {
//
////        def plotRect = Rectangle {
////            translateX: yLabelSpace
////            translateY: xLabelSpace
////            width: plotWidth
////            height: bind plotHeight
////            fill: Color.WHITE
////            smooth: false
////            stroke: Color.BLACK
////        }
////
////        //rectangle showing the normal range
////        def normRangeRect = Rectangle {
////                translateX: yLabelSpace + 1 //so that range view doesn't overlap left side of plot rectangle
////                translateY: bind (xLabelSpace + (yAxis.upperBound - maxRange) * yAxis.numPixPerUnit) + 1
////                width: plotWidth - 2    //-1 so that range view doesn't overlap right side of plot rectangle
////                height: bind ((maxRange - minRange) * yAxis.numPixPerUnit) - 2
////                fill: Color.CYAN
////                smooth: false
////            }
////
////        //label for x axis
////        def yLabel = createYLabel();
//
//        //background rectangle where the chart is plotted
////        var plotRect = bind createPointSeq(xSeries);
//
//        //sequence of data points
//        var pointSeq = bind createPointSeq(xSeries, ySeries);
//
//        var shapes = bind createShapes(xSeries);
//
//        return Group {
////                content: bind [ plotRect, yLabel, normRangeRect, pointSeq ]
//                content: bind [ shapes, pointSeq ]
//        }
//    }
//}
